package com.duyulong.demo.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.converter.StringHttpMessageConverter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

@Service
public class ChatService {
    private static final Logger logger = LoggerFactory.getLogger(ChatService.class);
    
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${zhipu.api.key}")
    private String apiKey;

    private static final String API_URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
    private static final int MAX_RETRIES = 3;
    private static final long RETRY_DELAY_MS = 10000;
    private static final long MIN_REQUEST_INTERVAL_MS = 5000;
    private static final int MAX_TOKENS = 2000;

    private final AtomicLong lastRequestTime = new AtomicLong(0);
    private final AtomicLong consecutiveFailures = new AtomicLong(0);


    private final OkHttpClient client;

    public ChatService() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
        logger.info("ChatService初始化完成，配置: 最大重试次数={}, 重试延迟={}ms, 最小请求间隔={}ms", 
                   MAX_RETRIES, RETRY_DELAY_MS, MIN_REQUEST_INTERVAL_MS);
    }

    public interface StreamCallback {
        void onMessage(String message);
        void onError(String error);
        void onComplete();
    }

    public void streamChat(String prompt, StreamCallback callback) {
        logger.info("开始处理流式对话请求，消息长度: {}", prompt.length());
        
        long currentTime = System.currentTimeMillis();
        long lastRequest = lastRequestTime.get();
        long timeSinceLastRequest = currentTime - lastRequest;
        
        if (timeSinceLastRequest < MIN_REQUEST_INTERVAL_MS) {
            long waitTime = MIN_REQUEST_INTERVAL_MS - timeSinceLastRequest;
            logger.warn("请求过于频繁，需要等待{}ms", waitTime);
            callback.onError("系统提示：请求过于频繁，请等待" + (waitTime / 1000) + "秒后再试");
            return;
        }
        
        lastRequestTime.set(currentTime);
        int retryCount = 0;
        
        while (retryCount <= MAX_RETRIES) {
            try {
                logger.info("准备发送请求，当前重试次数: {}", retryCount);
                
                String jsonBody = objectMapper.writeValueAsString(createRequestBody(prompt));
                RequestBody requestBody = RequestBody.create(
                    okhttp3.MediaType.parse("application/json; charset=utf-8"),
                    jsonBody
                );

                Request request = new Request.Builder()
                        .url(API_URL)
                        .post(requestBody)
                        .header("Authorization", "Bearer " + apiKey)
                        .header("Accept", "text/event-stream")
                        .build();

                logger.info("发送HTTP请求到智谱API");
                try (Response response = client.newCall(request).execute()) {
                    if (!response.isSuccessful()) {
                        String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                        logger.error("API请求失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                        
                        if (response.code() == 429) {
                            String error = "系统提示：服务器繁忙，请等待" + (RETRY_DELAY_MS / 1000) + "-" + 
                                         (RETRY_DELAY_MS * 2 / 1000) + "秒后再试";
                            callback.onError(error);
                            return;
                        }
                        
                        handleHttpError(response.code(), callback);
                        return;
                    }

                    logger.info("成功获取响应，开始处理流式数据");
                    ResponseBody responseBody = response.body();
                    if (responseBody == null) {
                        callback.onError("系统提示：服务器返回空响应");
                        return;
                    }

                    BufferedReader reader = new BufferedReader(new InputStreamReader(responseBody.byteStream(), StandardCharsets.UTF_8));
                    String line;
                    StringBuilder buffer = new StringBuilder();

                    while ((line = reader.readLine()) != null) {
                        if (line.isEmpty()) {
                            continue;
                        }

                        if (line.startsWith("data: ")) {
                            String data = line.substring(6).trim();
                            if ("[DONE]".equals(data)) {
                                logger.info("收到结束标记[DONE]");
                                callback.onComplete();
                                return;
                            }

                            try {
                                JsonNode jsonNode = objectMapper.readTree(data);
                                JsonNode deltaNode = jsonNode.path("choices")
                                        .path(0)
                                        .path("delta");

                                String role = deltaNode.path("role").asText(null);
                                String content = deltaNode.path("content").asText(null);

                                if (content != null && !content.isEmpty()) {
                                    buffer.append(content);
                                    // 当收集到完整的句子或达到一定长度时发送
                                    if (isCompleteSentence(buffer.toString()) || buffer.length() >= 50) {
                                        String message = filterResponse(buffer.toString());
                                        logger.info("发送消息片段，长度: {}", message.length());
                                        callback.onMessage(message);
                                        buffer.setLength(0);
                                    }
                                }
                            } catch (Exception e) {
                                logger.error("解析JSON响应失败: {}", e.getMessage());
                                callback.onError("系统提示：解析响应数据失败");
                                return;
                            }
                        }
                    }

                    // 发送剩余的内容
                    if (buffer.length() > 0) {
                        String message = buffer.toString();
                        logger.info("发送最后的消息片段，长度: {}", message.length());
                        callback.onMessage(message);
                    }
                }
                return;
            } catch (IOException e) {
                logger.error("请求发生IO异常", e);
                retryCount++;
                if (retryCount > MAX_RETRIES) {
                    logger.error("达到最大重试次数{}，停止重试", MAX_RETRIES);
                    callback.onError("系统提示：请求失败，建议等待1-2分钟后再试");
                    return;
                }
                
                long delayMs = calculateRetryDelay(retryCount);
                logger.info("准备第{}次重试，等待{}ms", retryCount, delayMs);
                try {
                    Thread.sleep(delayMs);
                } catch (InterruptedException ie) {
                    logger.warn("重试等待被中断");
                    Thread.currentThread().interrupt();
                    callback.onError("系统提示：请求被中断，请稍后重试");
                    return;
                }
            }
        }
    }

    private boolean isCompleteSentence(String text) {
        if (text.isEmpty()) {
            return false;
        }
        // 检查是否以句号、问号、感叹号、分号、冒号结尾
        char lastChar = text.charAt(text.length() - 1);
        return lastChar == '。' || lastChar == '？' || lastChar == '！' || 
               lastChar == '；' || lastChar == '：' || lastChar == '.' || 
               lastChar == '?' || lastChar == '!' || lastChar == ';' || 
               lastChar == ':' || lastChar == '\n';
    }

    private void handleHttpError(int statusCode, StreamCallback callback) {
        String error;
        switch (statusCode) {
            case 401:
                error = "智障提示：身份验证失败，让我找管理员看看密钥是不是过期了...";
                break;
            case 403:
                error = "智障提示：没有访问权限，我是不是走错门了？";
                break;
            case 404:
                error = "智障提示：找不到资源，可能是我记错地方了...";
                break;
            case 429:
                error = "智障提示：我有点累了，让我缓缓...";
                break;
            case 500:
                error = "智障提示：服务器好像傻掉了，等它清醒清醒...";
                break;
            default:
                error = "智障提示：遇到了奇怪的问题 (HTTP " + statusCode + ")，要不待会再试试？";
        }
        logger.error("HTTP错误: {}", error);
        callback.onError(error);
    }

    private long calculateRetryDelay(int retryCount) {
        return Math.min(RETRY_DELAY_MS * (1L << (retryCount - 1)), 60000);
    }

    public String chat(String prompt) {
        int retries = 0;
        String lastError = null;

        while (retries < MAX_RETRIES) {
            try {
                long waitTime = calculateWaitTime();
                if (waitTime > 0) {
                    TimeUnit.MILLISECONDS.sleep(waitTime);
                }
                lastRequestTime.set(System.currentTimeMillis());
                
                String response = sendChatRequest(prompt);
                consecutiveFailures.set(0);
                return response;
            } catch (HttpStatusCodeException e) {
                lastError = handleHttpError(e, ++retries);
                if (lastError.contains("请等待") || lastError.contains("系统繁忙")) {
                    try {
                        long delay = calculateRetryDelay(retries);
                        TimeUnit.MILLISECONDS.sleep(delay);
                        continue;
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        return "系统提示：请求被中断，请稍后重试";
                    }
                }
                return lastError;
            } catch (Exception e) {
                consecutiveFailures.incrementAndGet();
                lastError = handleGeneralError(e);
                if (lastError.contains("请等待") || lastError.contains("系统繁忙")) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(calculateRetryDelay(retries));
                        continue;
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        return "系统提示：请求被中断，请稍后重试";
                    }
                }
                return lastError;
            }
        }
        
        return lastError != null ? lastError : "系统提示：请求失败，请稍后重试";
    }

    private String handleHttpError(HttpStatusCodeException e, int retryCount) {
        HttpStatus status = e.getStatusCode();
        if (status == HttpStatus.TOO_MANY_REQUESTS) {
            long waitTime = RETRY_DELAY_MS * (long) Math.pow(1.5, retryCount - 1);
            return String.format("系统提示：系统繁忙，请等待%d秒后重试", waitTime / 1000);
        }
        return formatErrorMessage(e);
    }

    private String handleGeneralError(Exception e) {
        String message = e.getMessage();
        if (message != null && message.startsWith("系统提示：")) {
            return message;
        }
        return formatErrorMessage(e);
    }

    private long calculateWaitTime() {
        long now = System.currentTimeMillis();
        long timeSinceLastRequest = now - lastRequestTime.get();
        if (timeSinceLastRequest < MIN_REQUEST_INTERVAL_MS) {
            return MIN_REQUEST_INTERVAL_MS - timeSinceLastRequest;
        }
        return 0;
    }

    private String sendChatRequest(String prompt) throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
        headers.set("User-Agent", "Spring-Boot-Client");
        headers.set("Content-Type", "application/json;charset=UTF-8");
        headers.set("Accept-Charset", "UTF-8");

        ObjectNode requestBody = objectMapper.createObjectNode();
        requestBody.put("model", "glm-4");
        requestBody.put("temperature", 0.7);
        requestBody.put("top_p", 0.7);
        requestBody.put("max_tokens", 1000);
        
        ArrayNode messages = objectMapper.createArrayNode();
        ObjectNode message = objectMapper.createObjectNode();
        message.put("role", "user");
        message.put("content", prompt);
        messages.add(message);
        requestBody.set("messages", messages);

        String jsonBody = objectMapper.writeValueAsString(requestBody);
        HttpEntity<String> request = new HttpEntity<>(jsonBody, headers);

        ResponseEntity<String> response = restTemplate.postForEntity(API_URL, request, String.class);
        
        if (!response.getStatusCode().is2xxSuccessful()) {
            throw new RuntimeException("系统提示：服务器返回错误状态码：" + response.getStatusCode());
        }

        JsonNode responseJson = parseResponse(response.getBody());
        String content = responseJson.path("choices").path(0).path("message").path("content").asText();
        return content.isEmpty() ? "系统提示：AI暂时没有生成回复，请重试" : filterResponse(content);
    }

    @Autowired
    public void configureRestTemplate(RestTemplate restTemplate) {
        restTemplate.getMessageConverters().add(0, 
            new StringHttpMessageConverter(java.nio.charset.StandardCharsets.UTF_8));
    }

    private JsonNode parseResponse(String responseBody) throws Exception {
        if (responseBody == null || responseBody.isEmpty()) {
            throw new Exception("系统提示：服务器返回空响应");
        }
        try {
            return objectMapper.readTree(responseBody);
        } catch (Exception e) {
            throw new Exception("系统提示：解析响应失败，" + getChineseErrorMessage(e.getMessage()));
        }
    }

    private String filterResponse(String response) {
        if (response == null || response.isEmpty()) {
            return response;
        }
        
        // 第一步：替换产品和公司相关词汇
        String filtered = response
            // 替换智谱相关
            .replaceAll("(?i)智谱\\s*(AI|助手|科技|大模型)?", "智障")
            .replaceAll("(?i)Zhipu\\s*(AI|Assistant)?", "智障")
            .replaceAll("(?i)(智谱|zhipu)\\s*(api|Api|API)", "智障接口")
            .replaceAll("(?i)(智谱|zhipu)\\s*(chat|Chat|CHAT)", "智障聊天")
            
            // 替换模型名称
            .replaceAll("(?i)ChatGLM[\\-_]?(3|4|Turbo|Pro|Lite|std|standard)?", "智障模型")
            .replaceAll("(?i)GLM[\\-_]?(3|4|Turbo|Pro|Lite|std|standard)?", "智障模型")
            .replaceAll("(?i)(清言|Qianyan)[\\-_]?(pro|lite|std|standard)?", "智障")
            
            // 替换助手称谓
            .replaceAll("(?i)(智能助理|智能助手|AI助理|机器助手|机器人助理)", "智障")
            .replaceAll("(?i)\\b(assistant|bot|robot|chatbot)\\b", "智障")
            .replaceAll("(?i)(AI|人工智能)\\s*(助手|助理|机器人)", "智障");

        // 第二步：优化自我介绍和重复表述
        filtered = filtered
            // 处理开头的自我介绍
            .replaceAll("^(?i)(您好|你好|hello|hi)[,，!！.。]?\\s*(这里是|我是|作为|我将作为)?\\s*(一个|一位)?\\s*智障", "您好")
            .replaceAll("^(?i)智障[,，.。:：]?\\s*", "")
            
            // 处理重复的身份说明
            .replaceAll("(?i)智障\\s*[,，.。!！?？]\\s*智障", "智障")
            .replaceAll("(?i)智障[,，.。!！?？\\s]*的?智障", "智障")
            .replaceAll("(?i)作为智障[,，.。!！?？\\s]*我", "我")
            .replaceAll("(?i)我是智障[,，.。!！?？\\s]*我", "我")
            .replaceAll("(?i)(我是|作为|身为)(一个|一位)?智障[,，.。]?\\s*", "")
            
            // 处理特定句式
            .replaceAll("(?i)让我这个智障", "让我")
            .replaceAll("(?i)我作为(一个|一位)?智障", "我")
            .replaceAll("(?i)(您可以|可以|请)?问智障", "问我")
            .replaceAll("(?i)(让|希望|需要|由|交给|请|要)智障", "让我")
            
            // 处理句尾的身份说明
            .replaceAll("(?i)(这就是|以上就是|这是|这些就是|以上是)智障的?[^，。！？]*[，。！？]", "")
            .replaceAll("(?i)这是我作为智障[^，。！？]*[，。！？]", "")
            .replaceAll("(?i)我会作为智障[^，。！？]*[，。！？]", "")
            
            // 处理模型相关术语
            .replaceAll("(?i)(大模型|语言模型|基础模型|通用模型)", "智障模型")
            .replaceAll("(?i)\\b(LLM|GPT|LLaMA|Transformer)s?\\b", "智障模型")
            .replaceAll("(?i)(模型训练|预训练|微调)", "智障优化")
            
            // 处理特定场景表述
            .replaceAll("(?i)作为\\s*(一个|一位)?\\s*(AI|人工智能|智能|机器人)?\\s*(助手|助理|机器人)", "作为智障")
            .replaceAll("(?i)我是\\s*(一个|一位)?\\s*(AI|人工智能|智能|机器人)?\\s*(助手|助理|机器人)", "我是智障")
            .replaceAll("(?i)(让我|作为)\\s*(一个|一位)?\\s*(AI|人工智能|智能|机器人)?\\s*(来|为您|帮您|帮你|为你)", "让我");

        // 第三步：清理可能产生的多余空格和标点
        filtered = filtered
            .replaceAll("\\s+", " ")
            .replaceAll("([，。！？])\\s*([，。！？])", "$2")
            .replaceAll("^\\s+", "")
            .replaceAll("\\s+$", "");

        // 第四步：最终清理重复的智障表述
        filtered = filtered
            .replaceAll("(?i)智障\\s*[和与]\\s*智障", "智障")
            .replaceAll("(?i)智障\\s*[的地得]\\s*智障", "智障")
            .replaceAll("(?i)智障[^，。！？]{0,10}智障", "智障")
            .replaceAll("(?i)我[^，。！？]{0,10}智障[^，。！？]{0,10}我", "我")
            .replaceAll("(?i)智障[^，。！？]{0,10}我[^，。！？]{0,10}智障", "我");

        return filtered;
    }

    private String formatErrorMessage(Exception e) {
        if (e instanceof HttpStatusCodeException) {
            HttpStatusCodeException httpError = (HttpStatusCodeException) e;
            HttpStatus status = httpError.getStatusCode();
            String message;
            switch (status) {
                case UNAUTHORIZED:
                    message = "身份验证失败，请联系管理员检查授权信息";
                    break;
                case BAD_REQUEST:
                    message = "请求格式有误，请稍后重试";
                    break;
                case TOO_MANY_REQUESTS:
                    message = "系统繁忙，请稍后再试";
                    break;
                case INTERNAL_SERVER_ERROR:
                    message = "服务器暂时无法处理请求，请稍后再试";
                    break;
                default:
                    message = "请求遇到问题：" + getChineseStatusMessage(status);
            }
            return "系统提示：" + message;
        }
        return "系统提示：" + getChineseErrorMessage(e.getMessage());
    }

    private String getChineseErrorMessage(String englishMessage) {
        if (englishMessage == null) {
            return "我有点懵，不知道哪里出错了...";
        }
        if (englishMessage.startsWith("智障提示：")) {
            return englishMessage.substring(5);
        }
        if (englishMessage.contains("timeout")) {
            return "我等太久了，网络好像不太好...";
        } else if (englishMessage.contains("connection refused")) {
            return "服务器不理我，要不等会再试试？";
        } else if (englishMessage.contains("bad request")) {
            return "我好像说错话了，让我重新组织一下语言...";
        } else if (englishMessage.contains("unauthorized")) {
            return "我好像没带门禁卡，密钥可能有问题...";
        } else if (englishMessage.contains("too many requests")) {
            return "我说太快了，让我歇会儿...";
        } else {
            return "遇到了一些奇怪的问题，我也不太懂，要不重试一下？";
        }
    }

    private String getChineseStatusMessage(HttpStatus status) {
        switch (status) {
            case NOT_FOUND:
                return "找不到服务，可能是我迷路了";
            case SERVICE_UNAVAILABLE:
                return "服务器在休息，待会再来吧";
            case GATEWAY_TIMEOUT:
                return "服务器响应太慢了，要不重试一下";
            default:
                return "出了一些奇怪的问题，重试试试看";
        }
    }

    private ObjectNode createRequestBody(String prompt) {
        ObjectNode requestBody = objectMapper.createObjectNode();
        requestBody.put("model", "glm-4");
        requestBody.put("temperature", 0.7);
        requestBody.put("top_p", 0.7);
        requestBody.put("stream", true);
        requestBody.put("max_tokens", MAX_TOKENS);
        
        ArrayNode messages = objectMapper.createArrayNode();
        ObjectNode message = objectMapper.createObjectNode();
        message.put("role", "user");
        message.put("content", prompt);
        messages.add(message);
        requestBody.set("messages", messages);
        
        return requestBody;
    }
} 